/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月16日
 */
package com.massyframework.beanskin.web.servlet;

import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.web.ModularServletContext;
import com.massyframework.beanskin.web.utils.WebUtils;

/**
 * 提供关联{@link ServiceExportableModule}的Servlet基类
 * 
 * @author huangkh
 */
public abstract class ModuleServlet implements Servlet {

	private ModuleServletConfig servletConfig;

    public ModuleServlet() {
    }

    /**
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being placed into service.
     *
     * <p>The servlet container calls the <code>init</code>
     * method exactly once after instantiating the servlet.
     * The <code>init</code> method must complete successfully
     * before the servlet can receive any requests.
     *
     * <p>The servlet container cannot place the servlet into service
     * if the <code>init</code> method
     * <ol>
     * <li>Throws a <code>ServletException</code>
     * <li>Does not return within a time period defined by the Web server
     * </ol>
     *
     * @param config a <code>ServletConfig</code> object
     *               containing the servlet's
     *               configuration and initialization parameters
     * @throws ServletException if an exception has occurred that
     *                          interferes with the servlet's normal
     *                          operation
     * @see UnavailableException
     * @see #getServletConfig
     */
    @Override
    public final void init(ServletConfig config) throws ServletException {
        Module<?> module  = WebUtils.retrieveAssociateModule(config);
        this.servletConfig = this.createModuleServletConfig(module, config);
        this.init();
    }

    protected void init() throws ServletException{

    }

    /**
     * Returns a {@link ServletConfig} object, which contains
     * initialization and startup parameters for this servlet.
     * The <code>ServletConfig</code> object returned is the one
     * passed to the <code>init</code> method.
     *
     * <p>Implementations of this interface are responsible for storing the
     * <code>ServletConfig</code> object so that this
     * method can return it. The {@link GenericServlet}
     * class, which implements this interface, already does this.
     *
     * @return the <code>ServletConfig</code> object
     * that initializes this servlet
     * @see #init
     */
    @Override
    public ServletConfig getServletConfig() {
        return this.servletConfig;
    }

    /**
     * Returns information about the servlet, such
     * as author, version, and copyright.
     *
     * <p>The string that this method returns should
     * be plain text and not markup of any kind (such as HTML, XML,
     * etc.).
     *
     * @return a <code>String</code> containing servlet information
     */
    @Override
    public String getServletInfo() {
        return this.getClass().getSimpleName();
    }

    /**
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being taken out of service.  This method is
     * only called once all threads within the servlet's
     * <code>service</code> method have exited or after a timeout
     * period has passed. After the servlet container calls this
     * method, it will not call the <code>service</code> method again
     * on this servlet.
     *
     * <p>This method gives the servlet an opportunity
     * to clean up any resources that are being held (for example, memory,
     * file handles, threads) and make sure that any persistent state is
     * synchronized with the servlet's current state in memory.
     */
    @Override
    public void destroy() {

    }

    /**
     * 获取关联的模块
     * @return {@link Module}
     */
    protected Module<?> getAssociatedModule(){
        return this.servletConfig== null ? null :
                this.servletConfig.getAssociatedModule();
    }

    /**
     * 获取模块化的Servlet上下文
     * @return {@link ModularServletContext}
     */
    public ModularServletContext getModularServletContext(){
        return (ModularServletContext)this.servletConfig.getServletContext();
    }

    /**
     * 创建{@link ModuleServletConfig}
     * @param assembly {@link Module}, 转配件
     * @param origin {@link ServletConfig}, 原始的ServletConfig
     * @return {@link ModuleServletConfig}
     */
    protected ModuleServletConfig createModuleServletConfig(Module<?> module, ServletConfig origin){
        return new ModuleServletConfig(module, origin);
    }

}
